package frame;

import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
import constant.MapConstants;
import constant.Probabilities;
import dao.DatabaseConnection;
import model.Food;
import model.Player;
import model.Snake;
import type.Buff;
import type.Direction;
import type.GameMode;
import util.MultimediaIO;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Random;
import java.util.Vector;

import static constant.ColorConstants.*;
import static constant.MapElements.*;
import static constant.Probabilities.NORMAL_FOOD_PROB;
import static frame.MainFrame.GAME_MODE;
import static model.Food.*;

/**
 * 游戏面板类
 */
public class GamePanel extends JPanel implements KeyListener, Runnable {
    // 所属画框
    public MainFrame frame;
    // 画布尺寸
    public static final int width = 800;
    public static final int height = 620;

    // 地图数组大小
    public static final int ROW_NUM = 26;
    public static final int COL_NUM = 36;
    /**
     * 地图数组
     * / 0 - NULL 表示没有元素
     * / 1 - BORDER 表示地图边界
     * / 2 - WALL 表示墙
     * / 3 - SNAKE_HEAD 表示蛇头
     * / 4 - SNAKE_BODY 表示蛇身
     * / 5 - SNAKE_FOOD 表示食物
     */
    public int[][] map = new int[ROW_NUM][COL_NUM];
    private int mapType; // 本次游戏的地图类型
    public Snake snake; // 蛇
    public Vector<Food> foods; // 食物
    public int score = 0; // 得分
    public boolean isPaused = false; // 游戏是否暂停
    public long runTime = 0; // 游戏运行时间

    public boolean firstChange = false;
    public boolean secondChange = false;
    public boolean thirdChange = false;

    /**
     * 创建一个游戏界面窗口，并初始化游戏元素
     */
    public GamePanel(MainFrame frame) {
        this.frame = frame;
        addKeyListener(this);

        // 创建蛇
        if (frame.isIsDeveloper()) snake = new Snake(this, 15, 10, frame.getSnakeInitLengthSlider(),frame.getSnakeInitSpeedSlider());
        else snake=new Snake(this,15,10);
        // 创建食物集合
        foods = new Vector<>();

        // map 设置边界
        for (int i = 0; i < COL_NUM; i++) { // 上下边界
            map[0][i] = BORDER;
            map[ROW_NUM - 1][i] = BORDER;
        }
        for (int i = 0; i < ROW_NUM; i++) { // 左右边界
            map[i][0] = BORDER;
            map[i][COL_NUM - 1] = BORDER;
        }

        // 如果游戏模式为 ADVANCED 就生成地图
        if (GAME_MODE == GameMode.ADVANCED) {
//            mapType = (int)(Math.random() * 4 + 1); // 随机生成四张地图的其中一种
            MapConstants.generateMap(map, mapType);
        }

        new Thread(this).start();
    }

    /**
     * 绘制游戏界面信息
     */
    @Override
    public void paint(Graphics g) {
        super.paint(g);
        // 创建后备缓冲区，大小与窗口相同
        BufferedImage backBuffer = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);

        // 在后备缓冲区进行绘制操作
        Graphics2D g2 = backBuffer.createGraphics();
        // 绘制游戏网格
        int gridSize = 20;
        int gridOffsetX = 30; // 修改为视觉效果调整后的值
        int gridOffsetY = 50; // 修改为视觉效果调整后的值
        g2.setColor(Color.LIGHT_GRAY);
        for (int i = 0; i < ROW_NUM; i++) {
            for (int j = 0; j < COL_NUM; j++) {
                g2.drawRect(gridOffsetX + j * gridSize, gridOffsetY + i * gridSize, gridSize, gridSize);
            }
        }

        // 绘制游戏元素：边界、墙、蛇
        for (int i = 0; i < ROW_NUM; i++) {
            for (int j = 0; j < COL_NUM; j++) {
                switch (map[i][j]) {
                    case BORDER: // 地图边界
                        g2.setColor(BORDER_COLOR);
                        g2.fillRect(gridOffsetX + j * gridSize, gridOffsetY + i * gridSize, gridSize, gridSize);
                        break;
                    case WALL: // 墙
                        g2.setColor(WALL_COLOR);
                        g2.fillRect(gridOffsetX + j * gridSize, gridOffsetY + i * gridSize, gridSize, gridSize);
                        break;
                    case SNAKE_HEAD: // 蛇头
                        g2.setColor(HEAD_COLOR);
                        g2.fillRect(gridOffsetX + j * gridSize, gridOffsetY + i * gridSize, gridSize, gridSize);
                        break;
                    case SNAKE_BODY: // 蛇身
                        g2.setColor(BODY_COLOR);
                        g2.fillRect(gridOffsetX + j * gridSize, gridOffsetY + i * gridSize, gridSize, gridSize);
                        break;
                }
            }
        }
        // 绘制食物
        for (Food food : foods) {
            Color foodColor = null;
            switch (food.buff) {
                case NORMAL:
                    foodColor = NORMAL_FOOD_COLOR;
                    break;
                case SPEED_UP:
                    foodColor = SPEED_UP_FOOD_COLOR;
                    break;
                case SHIELD:
                    foodColor = SHIELD_FOOD_COLOR;
                    break;
                case THROUGH_WALL:
                    foodColor = THROUGH_WALL_FOOD_COLOR;
                    break;
            }
            g2.setColor(foodColor);
            g2.fillRect(gridOffsetX + food.col * gridSize, gridOffsetY + food.row * gridSize, gridSize, gridSize);
        }

        // 绘制分割线
        g2.setColor(Color.BLACK);
        g2.drawLine(0, 40, width, 40);

        // 绘制状态栏
        g2.setColor(Color.blue);
        g2.setFont(new Font("标准", Font.BOLD, 15));
        g2.drawString("速度：" + snake.speed, 20, 30);
        g2.drawString("长度：" + snake.length, 100, 30);
        g2.drawString("得分：" + score, 700, 30);
        if (GAME_MODE==GameMode.CLASSIC){
            g2.drawString("当前模式为:经典模式", 450, 30);
        }else g2.drawString("当前模式为:糖豆人模式", 450, 30);
        if (frame.isSoundCheckBox()){
            g2.drawString("音效已开启", 610, 30);
        }else g2.drawString("音效已关闭", 610, 30);

        // 绘制buff
        synchronized (snake.buffs) {
            Iterator<Buff> it = snake.buffs.iterator();
            while (it.hasNext()) {
                switch (it.next()) {
                    case SPEED_UP:
                        try {
                            BufferedImage speed_up_image = ImageIO.read(new File("src/static/加速.png"));
                            g.drawImage(speed_up_image, 200, 15, 20, 20, null);
                        } catch (IOException e) {
                            throw new RuntimeException(e);
                        }
                        break;
                    case SHIELD:
                        try {
                            BufferedImage speed_up_image = ImageIO.read(new File("src/static/护盾.png"));
                            g.drawImage(speed_up_image, 240, 15, 20, 20, null);
                        } catch (IOException e) {
                            throw new RuntimeException(e);
                        }
                        break;
                    case THROUGH_WALL:
                        try {
                            BufferedImage speed_up_image = ImageIO.read(new File("src/static/穿墙.png"));
                            g.drawImage(speed_up_image, 280, 15, 20, 20, null);
                        } catch (IOException e) {
                            throw new RuntimeException(e);
                        }
                        break;
                }
            }
        }

        // 将后备缓冲区一次性绘制到屏幕上（上面几步都用g2，只有这步用g）
        g.drawImage(backBuffer, 0, 0, null);
    }

    /**
     * 读取键盘信号并做出相应反馈
     * W/A/S/D 改变 snake 的方向
     * 空格/ESC 暂停游戏
     */
    @Override
    public void keyPressed(KeyEvent e) {
        int keyCode = e.getKeyCode();
        if (!isPaused && snake.isLive) {
            switch (keyCode) {
                // W/A/S/D，改变 snake 方向
                case KeyEvent.VK_W:
                    if (snake.direction != Direction.DOWN && snake.direction != Direction.UP && snake.moved) {
                        snake.direction = Direction.UP;
                        System.out.println("改变方向：上");
                        snake.moved = false;
                    }
                    break;
                case KeyEvent.VK_A:
                    if (snake.direction != Direction.RIGHT && snake.direction != Direction.LEFT && snake.moved) {
                        snake.direction = Direction.LEFT;
                        System.out.println("改变方向：左");
                        snake.moved = false;
                    }
                    break;
                case KeyEvent.VK_S:
                    if (snake.direction != Direction.UP && snake.direction != Direction.DOWN && snake.moved) {
                        snake.direction = Direction.DOWN;
                        System.out.println("改变方向：下");
                        snake.moved = false;
                    }
                    break;
                case KeyEvent.VK_D:
                    if (snake.direction != Direction.LEFT && snake.direction != Direction.RIGHT && snake.moved) {
                        snake.direction = Direction.RIGHT;
                        System.out.println("改变方向：右");
                        snake.moved = false;
                    }
                    break;

                // ESC键||空格键，弹出游戏暂停窗口
                case KeyEvent.VK_SPACE:
                case KeyEvent.VK_ESCAPE:
                    // 弹出游戏暂停窗口
                    isPaused = true;
                    showPauseDialog();
                    break;
            }
        }
    }

    /**
     * 在 showPauseDialog 方法中添加以下代码以显示带有文本框的游戏暂停对话框
     */
    private void showPauseDialog() {
        // 显示确认消息对话框
        int option = JOptionPane.showConfirmDialog(this, "游戏已暂停，是否继续？", "游戏暂停", JOptionPane.YES_NO_OPTION);
        if (option == JOptionPane.YES_OPTION) {
            // 继续游戏
            isPaused = false;
        } else {
            // 关掉游戏音乐
            if (MultimediaIO.isPlaying) MultimediaIO.toggleAudio();
            // 回到主界面
            MainViewPanel mainViewPanel = new MainViewPanel(frame);
            frame.setContentPane(mainViewPanel);
            mainViewPanel.requestFocusInWindow();
            frame.revalidate();
        }
    }

    /**
     * 游戏结束对话框
     */
    private void showGameOverDialog() {
        // 创建一个 JTextField 用于输入玩家名称
        JTextField playerNameField = new JTextField();

        // 创建一个 Object 数组来存储对话框中的组件
        Object[] message = {
                "请输入玩家名称:", playerNameField
        };

        // 显示带有文本框的确认消息对话框
        int option = JOptionPane.showConfirmDialog(this, message, "游戏结束,是否保存记录？", JOptionPane.OK_CANCEL_OPTION);
        if (option == JOptionPane.OK_OPTION) {
            String playerName = playerNameField.getText();
            // 在这里可以处理玩家名称的逻辑，比如保存到文件或传递给其他方法
//            System.out.println("玩家名称为: " + playerName);
//            System.out.println("玩家名称为: " + score);
            Player player = new Player(playerName,score);
            DatabaseConnection.addPlayer(player, GAME_MODE);

            // -------数据添加功能------
            // 继续游戏
            MainViewPanel mainViewPanel = new MainViewPanel(frame);
            frame.setContentPane(mainViewPanel);
            mainViewPanel.requestFocusInWindow();
            frame.revalidate();
        } else {
            // 回到主界面
            MainViewPanel mainViewPanel = new MainViewPanel(frame);
            frame.setContentPane(mainViewPanel);
            mainViewPanel.requestFocusInWindow();
            frame.revalidate();
        }
    }

    /**
     * 在随机的位置生成食物
     */
    private void generateFood() {
        // foods.size() 大于 1 且蛇无 SPEED_UP buff，直接返回
        if (!foods.isEmpty() && !snake.buffs.contains(Buff.SPEED_UP)) {
            return;
        }

        // foods.size() 为 0 且无 SPEED_UP buff, 随机生成一个食物
        if (foods.isEmpty() && !snake.buffs.contains(Buff.SPEED_UP)) {
            // 确定位置
            int randomRow = (int) (Math.random() * (ROW_NUM - 2)) + 1;
            int randomCol = (int) (Math.random() * (COL_NUM - 2)) + 1;
            while (map[randomRow][randomCol] != NULL) {
                randomRow = (int) (Math.random() * (ROW_NUM - 2)) + 1;
                randomCol = (int) (Math.random() * (COL_NUM - 2)) + 1;
            }
            // 生成食物
            Food food = createFood(this, randomRow, randomCol, snake.length);
            foods.add(food);
        }

        // 有 SPEED_UP buff，随机生成 5 个食物
        if (foods.size() <= 5 && snake.buffs.contains(Buff.SPEED_UP)) {
            while (foods.size() <= 5) {
                // 确定位置
                int randomRow = (int) (Math.random() * (ROW_NUM - 2)) + 1;
                int randomCol = (int) (Math.random() * (COL_NUM - 2)) + 1;
                while (map[randomRow][randomCol] != NULL) {
                    randomRow = (int) (Math.random() * (ROW_NUM - 2)) + 1;
                    randomCol = (int) (Math.random() * (COL_NUM - 2)) + 1;
                }
                // 生成食物
                Food food = createFood(this, randomRow, randomCol, snake.length);
                foods.add(food);
            }
        }
    }

    @Override
    public void run() {
        while (snake.isLive) {
            if (GAME_MODE == GameMode.ADVANCED) MapConstants.generateMap(map, mapType); // 更新墙
            generateFood(); // 生成食物
            repaint(); // 不断绘制图片
            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            runTime += 20;
        }

        // 游戏结束，弹出游戏结束提示窗口
        if (frame.isSoundCheckBox()){
            MultimediaIO.toggleAudio();
            String audioFilePathDead = "src/static/贪吃蛇作战挂了.wav"; // 替换为实际的音频文件路径
            MultimediaIO.playAudio(audioFilePathDead);
        }


        showGameOverDialog();
        System.out.println("游戏结束！");
    }

    @Override
    public void keyTyped(KeyEvent e) {}

    @Override
    public void keyReleased(KeyEvent e) {}
}
